/**
 *  Copyright (C) 2008-2013  Telosys project org. ( http://www.telosys.org/ )
 *
 *  Licensed under the GNU LESSER GENERAL PUBLIC LICENSE, Version 3.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *          http://www.gnu.org/licenses/lgpl.html
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package org.telosys.persistence.impl;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;

import org.telosys.common.TelosysRuntimeException;
import org.telosys.persistence.PersistenceManager;
import org.telosys.persistence.PersistenceManagerFactory;
import org.telosys.persistence.TelosysPersistenceException;
import org.telosys.persistence.dao.Provider;
import org.telosys.persistence.dao.ProviderImpl;
import org.telosys.persistence.database.Database;
import org.telosys.persistence.database.DatabaseManager;
import org.telosys.persistence.dbfeatures.DbFeatures;
import org.telosys.persistence.dbfeatures.SpecificSqlOperations;
import org.telosys.persistence.env.SqlQueryContainer;

/**
 * This is the "Database Manager" provider 
 * Each instance is associated with a Database ID
 * 
 * @author Laurent GUERIN
 *
 */
public class PersistenceManagerFactoryImpl implements PersistenceManagerFactory
{
	private int               databaseId        = 0 ;

	private Database          database          = null ;
	
	private String            mappingPattern    = null ;
	
	private Provider          provider          = null ; 
	
	private SqlQueryContainer sqlQueryContainer = null ;

	private DatabaseMetaData       databaseMetaData      = null ;
	
	private SpecificSqlOperations  specificSqlOperations = null ;

	/**
	 * Constructor 
	 * 
	 * @param databaseId
	 */
	public PersistenceManagerFactoryImpl(int databaseId) 
	{
		super();
		this.database =	DatabaseManager.getDatabase(databaseId);
		if ( null == database ) 
		{
			throw new TelosysRuntimeException("No database for id " + databaseId );
		}
		this.databaseId = databaseId ;
		
		//this.mappingPattern = database.getMappingClassPattern();
		this.mappingPattern = database.getDatabaseConfig().getMappingClassPattern();
		
		this.provider = new ProviderImpl( mappingPattern );
		
		//--- Init the container for named SQL queries (with the list of folders where ".sql" files are located)
		//this.sqlQueryContainer = new SqlQueryContainer( this.database.getSqlFolders() );
		this.sqlQueryContainer = new SqlQueryContainer( this.database.getDatabaseConfig().getSqlFolders() );
		
		

	}
	
	public int getDatabaseId() 
	{
		return this.databaseId ;
	}
	
	public String getMappingPattern() 
	{
		return this.mappingPattern ;
	}
	
    private Connection getConnection(int dbId) 
    {
        //--- Get a connection from the connection provider
        Connection dbCon = null;
        try
        {
            dbCon = DatabaseManager.getConnection( dbId );
        } catch (Exception e)
        {
            throw new TelosysRuntimeException("Cannot get connection for database #" + dbId , e);
        }
        return dbCon;
    }
    

	/**
	 * Provides a manager for the associated database
	 * 
	 * @return
	 */
	public PersistenceManager createPersistenceManager()
	{
		Connection connection = getConnection(this.databaseId);
		
		//SequenceDAO sequenceDAO = null ;  
		//return new PersistenceManagerImpl( this.databaseId, connection, this.provider, this.sqlQueryContainer, sequenceDAO );
		
		SpecificSqlOperations specificSqlOperations = getSpecificSqlOperations(connection);
		return new PersistenceManagerImpl( this.databaseId, connection, this.provider, this.sqlQueryContainer, specificSqlOperations );
	}

	public SpecificSqlOperations getSpecificSqlOperations(Connection connection)
	{
		if ( null == this.specificSqlOperations ) {
			// not yet defined 
			DatabaseMetaData databaseMetaData = getDatabaseMetaData(connection) ;
			
//			DbFeaturesProvider dbFeaturesProvider = new DbFeaturesProvider();
//			DbFeatures dbFeatures = dbFeaturesProvider.getDbFeatures(databaseMetaData);
			DbFeatures dbFeatures = this.database.getDbFeatures(databaseMetaData);
			this.specificSqlOperations = new SpecificSqlOperations(dbFeatures);
		}
		return this.specificSqlOperations;
	}

	public DatabaseMetaData getDatabaseMetaData(Connection connection)
	{
		if ( null == this.databaseMetaData ) {
			// not yet defined 
			DatabaseMetaData dbmb = null ;
			try {
				dbmb = connection.getMetaData();
			} catch (SQLException e) {
				throw new TelosysPersistenceException("Cannot get DB meta-data (SQL Error)", e);
			}
			this.databaseMetaData = dbmb ;
		}
		return this.databaseMetaData ;
	}
}
